<template>
  <my-dialog
    v-model="showDialog"
    title="语音录制"
    :width="400"
    :show-mark="false"
    :mark-close="false"
    draggable
  >
    <p class="record-prompt">温馨提示：可录制最大时长为60s</p>
    <div ref="recordRef" style="margin-top: 10px"></div>
    <p class="record-time" v-if="!showStart">
      0{{ minute }}:{{ second < 10 ? "0" + second : second }}
    </p>
    <p class="record-desc">{{ recordDesc }}</p>
    <template #footer>
      <el-button
        type="primary"
        :disabled="disabledStart"
        round
        @click="startRecord"
        v-show="showStart"
      >
        <SvgIcon icon-class="record" popper-class="record-icon" />
        开始</el-button
      >
      <el-button
        type="warning"
        round
        @click="isPause"
        v-show="showPlay"
        :disabled="minute === 1"
        style="margin-right: 20px"
      >
        <SvgIcon :icon-class="isPlay ? 'pause' : 'play'" popper-class="record-icon" />
        {{ isPlay ? "暂停" : "继续" }}</el-button
      >
      <el-button
        type="danger"
        round
        @click="endRecord"
        v-show="showEnd"
        style="margin-left: 20px"
      >
        <SvgIcon icon-class="end" popper-class="record-icon" />
        结束</el-button
      >
      <template v-if="isEnd"
        ><el-button type="primary" round @click="play" :disabled="disabledStart">
          <SvgIcon :icon-class="isPlay ? 'pause' : 'play'" popper-class="record-icon" />
          {{ isPlay ? "暂停" : "播放" }}</el-button
        >
        <el-button
          type="warning"
          :disabled="isPlay || disabledStart"
          round
          @click="startRecord"
          style="margin: 0 22px"
        >
          <SvgIcon icon-class="again" popper-class="record-icon" />
          重录</el-button
        >
        <el-button
          type="success"
          :disabled="isPlay || disabledStart"
          round
          @click="sendRecord"
          style="margin-left: 0"
        >
          <SvgIcon icon-class="send" popper-class="record-icon" />
          发送</el-button
        ></template
      >
    </template>
  </my-dialog>
</template>

<script lang="ts" setup>
import { ref, watch, nextTick, inject } from "vue";
import myDialog from "@/components/ui-components/dialog.vue";
import Recorder from "@/plugins/recorder";
import { ElMessage } from "element-plus";
import Spectrum from "@/plugins/spectrum";
import { useMessagePinia } from "@/pinia/messages";
import { useUserPinia } from "@/pinia/user";

const props = defineProps<{
  modelValue: boolean;
}>();

const emits = defineEmits<{
  (e: "update:modelValue", show: boolean): void;
}>();

const messageStore = useMessagePinia();
const userStore = useUserPinia();

const otherId = inject("otherId", { value: "" }) as { value: string };
// 更新滚动条
const updateScroll = inject("updateScroll") as () => void;
// 滚动到底部
const scrollBottom = inject("scrollBottom") as () => void;

/**
 * 是否显示录音对话框
 */
const showDialog = ref<boolean>(props.modelValue);
/**
 * 给包含录音动画元素的元素一个ref属性
 */
const recordRef = ref<HTMLDivElement>();

watch(
  () => showDialog.value,
  (newValue) => emits("update:modelValue", newValue)
);

const spectrum = ref<Spectrum>();
/**
 * 动画是否暂停播放(包括暂停录音或者暂停播放)
 */
const isPlay = ref<boolean>(false);
/**
 * 显示开始录音按钮
 */
const showStart = ref<boolean>(true);
/**
 * 显示暂停或者播放按钮
 */
const showPlay = ref<boolean>(false);
/**
 * 显示开始结束按钮
 */
const showEnd = ref<boolean>(false);
/**
 * 是否结束录音
 */
const isEnd = ref<boolean>(false);
/**
 * 录音的分钟
 */
const minute = ref<0 | 1>(0);
/**
 * 录音的秒数
 */
const second = ref<number>(0);
/**
 * 录音的描述语
 */
const recordDesc = ref<string>("");
/**
 * 是否禁止点击开始录音
 */
const disabledStart = ref<boolean>(false);
/**
 * 录音器实例
 */
let recorder: Recorder;
/**
 * 播放是否结束
 */
const isPlayEnd = ref<boolean>(false);

watch(
  () => props.modelValue,
  (newValue) => {
    if (newValue) {
      nextTick(() => {
        minute.value = 0;
        second.value = 0;
        recordDesc.value = "";
        if (!showStart.value) showStart.value = true;
        if (showPlay.value) showPlay.value = false;
        if (showEnd.value) showEnd.value = false;
        if (isEnd.value) isEnd.value = false;
        spectrum.value = new Spectrum({
          el: recordRef.value!,
          width: 350,
          height: 150,
        });
        if (!recorder) {
          recorder = new Recorder({
            sampleRate: 16000,
          });
          recorder.onprogress = ({ duration, data }) => {
            const currentSecond: number = Math.floor(duration);
            if (currentSecond === 2 && !isEnd.value && !showEnd.value)
              showEnd.value = true;
            if (currentSecond === 60) {
              minute.value = 1;
              second.value = 0;
              endRecord();
            } else second.value = currentSecond;
            spectrum.value?.draw(data);
          };

          recorder.onplaying = ({ duration, data }) => {
            second.value = Math.floor(duration);
            if (second.value === 60) {
              minute.value = 1;
              second.value = 0;
            }
            spectrum.value?.draw(data);
          };

          recorder.onplay = () => {
            minute.value = 0;
            second.value = 0;
          };

          recorder.onplayend = () => {
            isPlay.value = false;
            const totalTime: number = Math.floor(recorder.duration);
            if (totalTime === 60) {
              minute.value = 1;
              second.value = 0;
            } else second.value = totalTime;
            recordDesc.value = "录音时长";
            isPlayEnd.value = true;
          };
        }
      });
    } else {
      isPlay.value = false;
      setTimeout(
        () => spectrum.value?.destroyed().then(() => (spectrum.value = null as any)),
        300
      );
      disabledStart.value = false;
      // 释放内存
      recorder.destroy().then(() => (recorder = null as any));
      isPlayEnd.value = false;
    }
    showDialog.value = newValue;
  }
);

// 开始准备录音
const startRecord = () => {
  if (navigator?.mediaDevices) {
    disabledStart.value = true;
    navigator.mediaDevices
      .getUserMedia({ audio: true })
      .then(() => {
        recorder.start().then(() => {
          isEnd.value = false;
          minute.value = 0;
          second.value = 0;
          isPlay.value = true;
          showStart.value = false;
          showPlay.value = true;
          recordDesc.value = "正在录音...";
          disabledStart.value = false;
        });
      })
      .catch(() => {
        ElMessage({
          duration: 1500,
          message: "请手动打开录音权限",
          type: "error",
        });
        disabledStart.value = false;
      });
  } else
    ElMessage({
      duration: 1500,
      message: "您的浏览器不支持navigator.mediaDevices属性",
      type: "error",
    });
};

// 是否暂停录音
const isPause = () => {
  if (isPlay.value) {
    recorder.pause();
    recordDesc.value = "已暂停录音";
    isPlay.value = false;
  } else {
    recorder.resume();
    recordDesc.value = "正在录音...";
    isPlay.value = true;
  }
};

//结束录音
const endRecord = () => {
  recorder.stop();
  isPlay.value = false;
  showPlay.value = false;
  showEnd.value = false;
  isEnd.value = true;
  const allTime: number = Math.floor(recorder.duration);
  if (allTime < 60) second.value = allTime;
  else {
    minute.value = 1;
    second.value = 0;
  }
  recordDesc.value = "录音时长";
};

// 是否播放语音还是暂停语音
const play = () => {
  const allTime: number = Math.floor(recorder.duration);
  if (!isPlay.value) {
    try {
      recorder.getPlayTime();
      if (isPlayEnd.value) {
        recorder.play();
        isPlayEnd.value = false;
      } else recorder.resumePlay();
    } catch {
      recorder.play();
    }
    isPlay.value = true;
    recordDesc.value = `正在播放...(${allTime}s)`;
  } else {
    recorder.pausePlay();
    isPlay.value = false;
    recordDesc.value = `已暂停播放(${allTime}s)`;
  }
};

// 开始发送语音
const sendRecord = () => {
  const WavData: Blob = recorder.getWAVBlob();
  const id: string = new Date().getTime() + "";
  const chatDatas = messageStore.chatList.get(otherId.value);
  const blobUrl: string = URL.createObjectURL(WavData);
  if (chatDatas) {
    chatDatas.messagesDatas.set(id, {
      userId: userStore.user.userId,
      isLoading: true,
      message: blobUrl,
      isError: false,
      avatar: userStore.user.avatar,
      type: "voice",
      duration: recorder.duration,
    });
  }
  setTimeout(() => scrollBottom());
  const theMessData = chatDatas?.messagesDatas.get(id);
  emits("update:modelValue", false);
  messageStore
    .sendRecordMessage({
      otherId: otherId.value,
      file: WavData,
      duration: recorder.duration,
      id,
    })
    .then((code) => {
      if (code === 1) {
        URL.revokeObjectURL(blobUrl);
        setTimeout(() => {
          updateScroll();
          scrollBottom();
        }, 50);
      } else {
        ElMessage({
          type: "error",
          duration: 1500,
          message: code === -2 ? "发送失败，对方和自己不是好友关系" : "发送失败",
        });
        if (theMessData) {
          theMessData.isError = true;
          theMessData.isLoading = false;
        }
      }
    })
    .catch(() => {
      ElMessage({
        duration: 1500,
        message: "发送失败",
        type: "error",
      });
      if (theMessData) {
        theMessData.isError = true;
        theMessData.isLoading = false;
      }
    });
};
</script>

<style lang="scss" scoped>
.record {
  &-icon {
    margin-right: 3px;
  }

  &-prompt {
    font-size: 10px;
    margin: -12px 0 0;
    text-align: center;
    color: $dimFontCor;
  }

  &-time {
    text-align: center;
    margin: 0;
    color: rgb(138, 136, 136);
  }

  &-desc {
    text-align: center;
    margin: 5px 0 0;
  }
}
</style>
